package com.ruoyi.law.service.impl;

import cn.felord.payment.wechat.v3.WechatApiProvider;
import cn.felord.payment.wechat.v3.WechatDirectPayApi;
import cn.felord.payment.wechat.v3.WechatResponseEntity;
import cn.felord.payment.wechat.v3.model.Amount;
import cn.felord.payment.wechat.v3.model.PayParams;
import cn.felord.payment.wechat.v3.model.Payer;
import cn.felord.payment.wechat.v3.model.TransactionQueryParams;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.law.domain.dto.LawOrderDTO;
import com.ruoyi.law.domain.entity.*;
import com.ruoyi.law.domain.query.LawOtherOrderQuery;
import com.ruoyi.law.domain.query.LawVipOrderQuery;
import com.ruoyi.law.enums.OrderState;
import com.ruoyi.law.enums.OrderType;
import com.ruoyi.law.enums.PayType;
import com.ruoyi.law.enums.VipType;
import com.ruoyi.law.mapper.LawOrderMapper;
import com.ruoyi.law.service.*;
import com.ruoyi.law.utils.OrderUtil;
import com.ruoyi.law.utils.SmsUtil;
import com.ruoyi.system.service.ISysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>
 * 律师订单 服务实现类
 * </p>
 *
 * @author code
 * @since 2022-11-23
 */
@Slf4j
@Service
public class LawOrderServiceImpl extends ServiceImpl<LawOrderMapper, LawOrder> implements ILawOrderService {

    @Value("${wechat.pay.v3.miniApp.app-id}")
    private String appid;
    @Value("${wechat.pay.v3.miniApp.mch-id}")
    private String mchId;
    @Value("${wechat.pay.v3.miniApp.mch-key}")
    private String mchKey;
    @Autowired
    private WechatApiProvider wechatApiProvider;
    @Autowired
    private ISysUserService userService;
    @Autowired
    private ILawVipService vipService;
    @Autowired
    private ILawServiceService serviceService;
    @Autowired
    private ILawEarningRecordService earningRecordService;
    @Autowired
    private ILawTeamService teamService;
    @Autowired
    private LawOrderMapper orderMapper;

    @Override
    public WechatResponseEntity<ObjectNode> generateVipOrder(LawVipOrderQuery vipOrderQuery) {
        Long userId = SecurityUtils.getUserId();
        String orderNum = OrderUtil.getOrderNum(userId);

        LawOrder lawOrder = new LawOrder();
        BigDecimal price = vipOrderQuery.getPrice();
        lawOrder.setOrderType(OrderType.VIP.getType());
        lawOrder.setPrice(price);
        lawOrder.setNum(orderNum);
        lawOrder.setUid(userId);
        lawOrder.setVipId(VipType.getVipId(vipOrderQuery.getVipType()));
        super.save(lawOrder);

        // 微信统一下单
        WechatDirectPayApi miniApp = wechatApiProvider.directPayApi("miniApp");
        // 获取vip名称
        String nameByVipType = vipService.getNameByVipType(vipOrderQuery.getVipType());
        // 生成微信所需参数
        PayParams payParams = getPayParams(price, orderNum, nameByVipType);
        return miniApp.jsPay(payParams);
    }

    @Override
    public WechatResponseEntity<ObjectNode> generateOtherOrder(LawOtherOrderQuery otherOrderQuery) {
        Long userId = SecurityUtils.getUserId();
        String orderNum = OrderUtil.getOrderNum(userId);
        LawService lawService = serviceService.getById(otherOrderQuery.getConsultingId());

        LawOrder lawOrder = new LawOrder();
        BigDecimal price = otherOrderQuery.getPrice();
        lawOrder.setOrderType(otherOrderQuery.getOrderType());
        lawOrder.setPrice(price);
        lawOrder.setNum(orderNum);
        lawOrder.setUid(userId);
        lawOrder.setConsultingId(otherOrderQuery.getConsultingId());
        // 咨询订单时长
        lawOrder.setOrderTime(otherOrderQuery.getOrderTime());
        // 支付方式: 微信支付
        lawOrder.setWay(otherOrderQuery.getPayType());
        // 分配的律师
        lawOrder.setLawyerId(otherOrderQuery.getTeamId());
        // 律师提成比例
        Integer lawyer = lawService.getLawyer();
        lawOrder.setLawyerPercent(lawyer);
        // 手机号
        lawOrder.setFillInPhone(otherOrderQuery.getFillInPhone());
        super.save(lawOrder);

        // 微信支付才需要统一下单
        if (StrUtil.equals(otherOrderQuery.getPayType(), PayType.wechatPay.getValue())) {
            // 微信统一下单
            WechatDirectPayApi miniApp = wechatApiProvider.directPayApi("miniApp");
            // 获取服务名称
            String serviceName = lawService.getTitle();
            // 生成微信所需参数
            PayParams payParams = getPayParams(price, orderNum, serviceName);
            return miniApp.jsPay(payParams);
        }
        return null;
    }

    /**
     * 得到支付参数
     *
     * @param orderNum    订单num
     * @param price       价格
     * @param description 描述
     * @return {@link PayParams}
     */
    private PayParams getPayParams(BigDecimal price, String orderNum, String description) {
        PayParams payParams = new PayParams();
        payParams.setAppid(appid);
        payParams.setMchid(mchId);
        payParams.setDescription(description);
        payParams.setOutTradeNo(orderNum);
        payParams.setNotifyUrl("/order/transaction");

        Amount amount = new Amount();
        amount.setTotal(price.multiply(new BigDecimal(100)).intValue());
        payParams.setAmount(amount);

        Payer payer = new Payer();
        SysUser user = SecurityUtils.getLoginUser().getUser();
        log.info("user: {}", user);
        payer.setOpenid(user.getOpenid());
        payParams.setPayer(payer);
        return payParams;
    }

    @Override
    public LawOrder getByOrderNum(String num) {
        LambdaQueryWrapper<LawOrder> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(LawOrder::getNum, num);
        return super.getOne(queryWrapper, false);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateOrder(LawOrder lawOrder) {
        // 已支付+已分配律师就是进行中
        lawOrder.setState(OrderState.paid.getValue());
        super.updateById(lawOrder);

        Long uid = lawOrder.getUid();
        SysUser orderUser = userService.selectUserById(uid);

        String orderType = lawOrder.getOrderType();
        if (OrderType.VIP.getType().equals(orderType)) {
            // 更新用户vip信息
            updateUserVipInfo(orderUser, lawOrder);
        }
        // 给一二级推荐人分红
        shareOutBonus(orderUser, lawOrder);
        // 咨询和服务 给律师提成
        if (OrderType.consultingOrder.getType().equals(orderType)
                || OrderType.serviceOrder.getType().equals(orderType)) {
            if (ObjectUtil.isNotNull(lawOrder.getLawyerId())) {
                // 给律师提成
                giveLawyerBonus(lawOrder);
            }

        }
    }

    /**
     * 给律师奖金
     *
     * @param lawOrder 订单
     */
    private void giveLawyerBonus(LawOrder lawOrder) {
        Long teamId = lawOrder.getLawyerId();
        LawTeam lawTeam = teamService.getById(teamId);

        String orderType = lawOrder.getOrderType();
        if (OrderType.consultingOrder.getType().equals(orderType)
                || OrderType.serviceOrder.getType().equals(orderType)) {
            // 咨询订单
            BigDecimal price = lawOrder.getPrice();
            BigDecimal lawyerPercent = new BigDecimal(lawOrder.getLawyerPercent());
            // 律师收益(四舍五入保留两位小数)
            BigDecimal lawyerBonus = price.multiply(lawyerPercent)
                    .divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
            // 律师收入
            BigDecimal oldPrice = lawTeam.getPrice() == null ? BigDecimal.ZERO : lawTeam.getPrice();
            lawTeam.setPrice(oldPrice.add(lawyerBonus));
            teamService.updateById(lawTeam);
            // 查询服务名称
            String serviceName = serviceService.getName(lawOrder.getConsultingId(), orderType);

            // 律师收入记录
            saveRecord(lawOrder.getNum(), lawOrder.getConsultingId()
                    , lawTeam.getId(), lawyerBonus, serviceName, orderType);
        }
    }

    @Override
    public Page<LawOrderDTO> myPage(Page<LawOrderDTO> toPage, LawOrderDTO lawOrderDTO) {
        Page<LawOrderDTO> page = orderMapper.myPage(toPage, lawOrderDTO);
        for (LawOrderDTO order : page.getRecords()) {
            String fillInPhone = order.getFillInPhone();
            // 如果填写了手机号，就用填写的手机号
            if (StrUtil.isNotBlank(fillInPhone)) {
                order.setPhone(fillInPhone);
            }

            String orderType = order.getOrderType();
            if (OrderType.VIP.getType().equals(orderType)) {
                // vip类型
                Long vipId = order.getVipId();
                LawVip lawVip = vipService.getById(vipId);
                order.setVipType(lawVip == null ? "" : lawVip.getName());
            } else if (OrderType.consultingOrder.getType().equals(orderType)
                    || OrderType.serviceOrder.getType().equals(orderType)) {
                // 咨询或服务类型
                Long consultingId = order.getConsultingId();
                LawService lawService = serviceService.getById(consultingId);
                order.setConsultingName(lawService == null ? "" : lawService.getTitle());
            }
            // 邀请人信息
            Long invitationId = order.getInvitationId();
            if (invitationId != null) {
                SysUser user = userService.selectUserById(invitationId);
                order.setInvitationName(user.getNickName());
            }
        }
        return page;
    }

    @Override
    public Map<String, Object> queryOrders(String orderNum) {
        WechatDirectPayApi miniApp = wechatApiProvider.directPayApi("miniApp");

        TransactionQueryParams transactionQueryParams = new TransactionQueryParams();
        transactionQueryParams.setMchId(mchId);
        transactionQueryParams.setTransactionIdOrOutTradeNo(orderNum);
        WechatResponseEntity<ObjectNode> responseEntity = miniApp.queryTransactionByOutTradeNo(transactionQueryParams);
        ObjectNode body = responseEntity.getBody();
        String tradeState = body.get("trade_state").asText();
        Map<String, Object> res = new HashMap<>(2);
        res.put("tradeState", tradeState);
        res.put("tradeStateDesc", body.get("trade_state_desc").asText());

        // 如果支付成功
        if (StrUtil.equals("SUCCESS", tradeState)) {
            LawOrder lawOrder = getByOrderNum(orderNum);
            // 如果是未支付则更新为已支付 并分红
            if (StrUtil.equals(lawOrder.getState(), OrderState.notPaid.getValue())) {
                updateOrder(lawOrder);
            }
        }

        return res;
    }

    @Override
    public Map<String, Object> queryFileOrders(String orderNum) {
        WechatDirectPayApi miniApp = wechatApiProvider.directPayApi("miniApp");

        TransactionQueryParams transactionQueryParams = new TransactionQueryParams();
        transactionQueryParams.setMchId(mchId);
        transactionQueryParams.setTransactionIdOrOutTradeNo(orderNum);
        WechatResponseEntity<ObjectNode> responseEntity = miniApp.queryTransactionByOutTradeNo(transactionQueryParams);
        ObjectNode body = responseEntity.getBody();
        String tradeState = body.get("trade_state").asText();
        Map<String, Object> res = new HashMap<>(2);
        res.put("tradeState", tradeState);
        res.put("tradeStateDesc", body.get("trade_state_desc").asText());

        return res;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void changeRatio(Long id, Integer ratio) {
        LawOrder lawOrder = super.getById(id);
        // 已支付的订单才将修改的提成补给用户
        if (StrUtil.equals(lawOrder.getState(), OrderState.paid.getValue())) {
            // 以前的提成比例
            Integer oldPercent = lawOrder.getLawyerPercent();
            BigDecimal price = lawOrder.getPrice();
            // teamId
            Long lawyerId = lawOrder.getLawyerId();
            LawTeam lawTeam = teamService.getById(lawyerId);
            Long userId = lawTeam.getUserId();
            SysUser teamUser = userService.selectUserById(userId);
            BigDecimal amount = teamUser.getAmount() == null ? BigDecimal.ZERO : teamUser.getAmount();
            // 以前的提成金额(四舍五入)
            BigDecimal oldAmount = price.multiply(new BigDecimal(oldPercent))
                    .divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
            // 新的提成金额(四舍五入)
            BigDecimal newAmount = price.multiply(new BigDecimal(ratio))
                    .divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
            amount = amount.add(newAmount).subtract(oldAmount);
            teamUser.setAmount(amount);
            userService.updateUser(teamUser);
            lawOrder.setLawyerPercent(ratio);
            saveRecord(lawOrder.getNum(), lawOrder.getConsultingId(), teamUser.getUserId(),
                    newAmount.subtract(oldAmount), "修改律师提成变化的费用", lawOrder.getOrderType());
            super.updateById(lawOrder);
        }
    }

    @Override
    public void closeOrder(Long id) {
        super.update(Wrappers.<LawOrder>lambdaUpdate()
                .set(LawOrder::getState, OrderState.completed.getValue())
                .eq(LawOrder::getId, id));
    }

    @Override
    public WechatResponseEntity<ObjectNode> payOrder(Long orderId) {
        LawOrder lawOrder = super.getById(orderId);
        Assert.notNull(lawOrder, "订单不存在");
        String state = lawOrder.getState();
        BigDecimal price = lawOrder.getPrice();
        String orderNum = lawOrder.getNum();
        String orderType = lawOrder.getOrderType();
        Assert.isTrue(StrUtil.equals(state, OrderState.notPaid.getValue()), "订单已支付");

        // 微信统一下单
        WechatDirectPayApi miniApp = wechatApiProvider.directPayApi("miniApp");
        // 获取服务名称
        String serviceName = "";
        if (OrderType.serviceOrder.getType().equals(orderType) || OrderType.consultingOrder.getType().equals(orderType)) {
            Long consultingId = lawOrder.getConsultingId();
            LawService lawService = serviceService.getById(consultingId);
            Assert.notNull(lawService, "服务名称不存在");
            serviceName = lawService.getTitle();
        } else if (OrderType.VIP.getType().equals(orderType)) {
            Long vipId = lawOrder.getVipId();
            LawVip lawVip = vipService.getById(vipId);
            Assert.notNull(lawVip, "VIP名称不存在");
            serviceName = lawVip.getName();
        }
        // 生成微信所需参数
        PayParams payParams = getPayParams(price, orderNum, serviceName);
        return miniApp.jsPay(payParams);
    }

    @Override
    public Map<String, Object> generateFileOrder(BigDecimal price) {
        Long userId = SecurityUtils.getUserId();
        String orderNum = OrderUtil.getOrderNum(userId);

        LawOrder lawOrder = new LawOrder();
        lawOrder.setOrderType(OrderType.fileOrder.getType());
        lawOrder.setPrice(price);
        lawOrder.setNum(orderNum);
        lawOrder.setUid(userId);
        super.save(lawOrder);

        // 微信统一下单
        WechatDirectPayApi miniApp = wechatApiProvider.directPayApi("miniApp");
        // 生成微信所需参数
        PayParams payParams = getPayParams(price, orderNum, OrderType.fileOrder.getName());
        WechatResponseEntity<ObjectNode> responseEntity = miniApp.jsPay(payParams);
        Map<String, Object> map = new HashMap<>(2);
        map.put("ordeNum", orderNum);
        map.put("payParams", responseEntity.getBody());
        return map;
    }

    /**
     * 更新用户vip信息
     *
     * @param orderUser 订单用户
     * @param vipOrder  vip订单
     */
    private void updateUserVipInfo(SysUser orderUser, LawOrder vipOrder) {
        Long vipId = vipOrder.getVipId();
        LawVip vip = vipService.getById(vipId);
        orderUser.setVipId(vipId);

        Integer day = vip.getDay();
        // 获取用户vip到期时间，如果没有则默认为当前时间
        Date vipDueDate = orderUser.getVipDueDate();
        if (vipDueDate == null) {
            vipDueDate = new Date();
        }
        // 到期时间加上购买的天数day
        Date newVipDueDate = DateUtil.offsetDay(vipDueDate, day);
        orderUser.setVipDueDate(newVipDueDate);
        userService.updateUser(orderUser);
    }

    /**
     * 给一二级推荐人分红
     *
     * @param lawOrder vip订单
     */
    private void shareOutBonus(SysUser orderUser, LawOrder lawOrder) {
        Long invitationId = orderUser.getInvitationId();
        if (invitationId != null) {
            String orderType = lawOrder.getOrderType();
            if (OrderType.VIP.getType().equals(orderType)) {
                Long vipId = lawOrder.getVipId();
                BigDecimal price = lawOrder.getPrice();
                LawVip vip = vipService.getById(vipId);
                Integer one = vip.getOne();
                // 给一级推荐人分红
                SysUser user = userService.selectUserById(invitationId);
                BigDecimal oneMoney = price.multiply(new BigDecimal(one))
                        .divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
                BigDecimal amount = user.getAmount() == null ? BigDecimal.ZERO : user.getAmount();
                user.setAmount(amount.add(oneMoney));
                userService.updateUser(user);

                // 写入收益记录表
                saveRecord(lawOrder.getNum(), vipId, user.getUserId(), oneMoney, "一级级推荐奖励", orderType);
                // 分红后发送短信
                try {
                    SmsUtil.send1(user.getPhonenumber(), user.getRemark() == null ? user.getNickName() : user.getRemark());
                } catch (Exception e) {
                    log.error("发送短信失败", e);
                }

                // 给二级推荐人分红
                Long twoInvitationId = user.getInvitationId();
                if (twoInvitationId != null) {
                    Integer two = vip.getTwo();
                    SysUser twoUser = userService.selectUserById(twoInvitationId);
                    BigDecimal twoMoney = price.multiply(new BigDecimal(two))
                            .divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
                    BigDecimal twoUserAmount = twoUser.getAmount() == null ? BigDecimal.ZERO : twoUser.getAmount();
                    twoUser.setAmount(twoUserAmount.add(twoMoney));
                    userService.updateUser(twoUser);

                    // 写入收益记录表
                    saveRecord(lawOrder.getNum(), vipId, twoUser.getUserId(), twoMoney, "二级推荐奖励", orderType);
                    // 分红后发送短信
                    try {
                        SmsUtil.send1(twoUser.getPhonenumber(), twoUser.getRemark() == null ? twoUser.getNickName() : twoUser.getRemark());
                    } catch (Exception e) {
                        log.error("发送短信失败", e);
                    }
                }
            } else if (OrderType.consultingOrder.getType().equals(orderType)
                    || OrderType.serviceOrder.getType().equals(orderType)) {
                // 咨询或服务类型
                Long consultingId = lawOrder.getConsultingId();
                LawService lawService = serviceService.getById(consultingId);
                Integer yi = lawService.getYi();
                BigDecimal price = lawOrder.getPrice();
                // 给一级推荐人分红
                SysUser user = userService.selectUserById(invitationId);
                BigDecimal amount = user.getAmount() == null ? BigDecimal.ZERO : user.getAmount();
                user.setAmount(amount.add(price.multiply(new BigDecimal(yi))
                        .divide(new BigDecimal(100), 2, RoundingMode.HALF_UP)));
                userService.updateUser(user);

                // 写入收益记录表
                saveRecord(lawOrder.getNum(), consultingId, user.getUserId(), price, "一级级推荐奖励", orderType);
                // 分红后发送短信
                try {
                    SmsUtil.send1(user.getPhonenumber(), user.getRemark() == null ? user.getNickName() : user.getRemark());
                } catch (Exception e) {
                    log.error("发送短信失败", e);
                }

                // 给二级推荐人分红
                Long twoInvitationId = user.getInvitationId();
                if (twoInvitationId != null) {
                    Integer er = lawService.getEr();
                    SysUser twoUser = userService.selectUserById(twoInvitationId);
                    BigDecimal twoUserAmount = twoUser.getAmount() == null ? BigDecimal.ZERO : twoUser.getAmount();
                    twoUser.setAmount(twoUserAmount.add(price.multiply(new BigDecimal(er))
                            .divide(new BigDecimal(100), 2, RoundingMode.HALF_UP)));
                    userService.updateUser(twoUser);

                    // 写入收益记录表
                    saveRecord(lawOrder.getNum(), consultingId, twoUser.getUserId(), price, "二级推荐奖励", orderType);
                    // 分红后发送短信
                    try {
                        SmsUtil.send1(twoUser.getPhonenumber(), twoUser.getRemark() == null ? twoUser.getNickName() : twoUser.getRemark());
                    } catch (Exception e) {
                        log.error("发送短信失败", e);
                    }
                }
            }
        }
    }

    /**
     * 写入收益记录表
     *
     * @param serviceId   项目id(包括服务id，咨询id，vipid)
     * @param num         订单号
     * @param userId      用户id
     * @param remark      备注
     * @param earningType 收入类型
     * @param price       价格
     */
    private void saveRecord(String num, Long serviceId, Long userId, BigDecimal price, String remark, String earningType) {
        LawEarningRecord record;
        record = new LawEarningRecord();
        record.setUserId(userId);
        record.setNum(num);
        record.setEarningType(earningType);
        record.setServiceId(serviceId);
        record.setPrice(price);
        record.setRemark(remark);
        earningRecordService.save(record);
    }

}
